package GA;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public abstract class AGA 
{
	Map<String, Method> map;
	
	ArrayList<AGA.Action> actions;
	
	static int[][] current_board;
	static int[][] new_board;
	private GAPlayer player;
	public ChromosomePair chromosome;
	
	protected AGA(GAPlayer pl)
	{
		actions = new ArrayList<AGA.Action>();
		order();
		player = pl;
		chromosome = new ChromosomePair(pl.weights(), pl.choices());
		
		build(pl);
		actions.trimToSize();
	}
	
	protected AGA(GAPlayer pl, ChromosomePair gene)
	{
		actions = new ArrayList<AGA.Action>();
		order();
		player = pl;
		this.chromosome = gene.clone();
		
		build(pl);
		actions.trimToSize();
	}
	
	protected AGA() 
	{
		
	}

	public abstract void build(GAPlayer pl);
	
	
	public AGA action(String name)
	{
		actions.add(new Action(name, this));
		return this;
	}
	
	public AGA weights(int index)
	{
		actions.get(actions.size()-1).actionIndex = index;
		return this;
	}
	
	public AGA when(Method isWhen, Method params)
	{
		actions.get(actions.size()-1).criterion = isWhen;
		actions.get(actions.size()-1).params = params;
		return this;
	}
	
	public AGA gives(int index) 
	{
		actions.get(actions.size()-1).wisenessIndex = index;
		return this;
	}

	public AGA gives(float ret) 
	{
		actions.get(actions.size()-1).wiseness = ret;
		
		return this;
	}
	
	@SuppressWarnings("unchecked")
	public void order()
	{
		Collections.sort(actions);
	}
	
	public float analyzeBrickSituation(int i)
	{
		order();
		float test = 0;
		
//		for(int j : gene.YChromosome)
//		{
//			switch(j)
//			{
//				case 0:
//					if(fir(i,map.get("hitOpponentHome"),map.get("twoboards_param")))
//						return 5;
//				case 1:
//					if(fir(i,map.get("moveOut"),map.get("twoboards_param")))
//						return 4;
//				case 2:
//					if(fir(i,map.get("hitMySelfHome"),map.get("twoboards_param")))
//						return (float)0.1;
//				case 3:
//					if(fir(i,map.get("reachStar"),map.get("futureSteps_param")))
//						return 3;
//				case 4:
//					if(fir(i,map.get("atHome"),map.get("futureSteps_param")))
//						return 6;
//				case 5:
//					if(fir(i,map.get("inDanger"),map.get("brickID_param")))
//						return 7;
//				case 6:
//					if(fir(i,map.get("almostHome"),map.get("brickID_param")))
//						return 9;
//				case 7:
//					if(fir(i,map.get("closeToHome"),map.get("brickID_param")))
//						return 7;
//				case 8:
//					if(fir(i,map.get("groupingBricks"),map.get("futureSteps_param")))
//						return 4;
//				case 9:
//					if(fir(i,map.get("movingFromGroup"),map.get("brickID_param")))
//						return 2;
//				default:
//					return 1;
//			}
//		}
		
		for(Action act : actions)
		{
			test = act.doAction(i);
			if(test!=0)
				break;
		}
		
		return test;
	}
	
//	private boolean fir(int i, Method criterion,Method params)
//	{
//		try 
//		{	Object[] parameters = new Object[1];
//			parameters[0] = i;
//			Object[] obj = (Object[]) params.invoke(player, parameters);
//			Boolean b = (Boolean)criterion.invoke(player, (Object[])
//					params.invoke(player, parameters)
//					);
//			
//			if((Boolean)criterion.invoke(player, (Object[])
//					params.invoke(player, parameters)
//					))
//				return true;
//			else
//				return false;
//	
//		} 
//		catch (IllegalArgumentException e) 
//		{
//			e.printStackTrace();
//		} 
//		catch (IllegalAccessException e) 
//		{
//			e.printStackTrace();
//		} 
//		catch (InvocationTargetException e) 
//		{
//			e.printStackTrace();
//		}
//		return false;
//	}

	//////////////////////////////////////////
	/* Inner classes */
	@SuppressWarnings("rawtypes")
	public class Action implements Comparable<Action>
	{
		public float wiseness;
		String name;
		private AGA geneInterface;
		int actionIndex = -1;
		Method criterion = null;
		Method params = null;
		int wisenessIndex = -1;
		
		
		public Action(String name, AGA ga)
		{
			this.name = name;
			this.geneInterface = ga;
		}


		@Override
		public int compareTo(Action o)
		{
			return 	this.actionIndex != -1 ?
						o.actionIndex != -1 ?
							chromosome.YChromosome[this.actionIndex].getInteger() == o.geneInterface.chromosome.YChromosome[o.actionIndex].getInteger() ?
								0
							:chromosome.YChromosome[this.actionIndex].getInteger() > o.geneInterface.chromosome.YChromosome[o.actionIndex].getInteger() ?
								-1 : 1
						: -1
					 : 1;
		}
		
		public float doAction(int i)
		{
			Object[] parameters = new Object[1];
			parameters[0] = i;
			
			if(criterion != null && params != null)
				return methodFiring(parameters)?
						wisenessIndex==-1 ? wiseness :
						(float)chromosome.XChromosome[wisenessIndex].getInteger():(float)0;
			else
				return wisenessIndex==-1 ? wiseness : (float)chromosome.XChromosome[wisenessIndex].getInteger();
		}
		
		@SuppressWarnings("unused")
		private Boolean methodFiring(Object[] parameters)
		{
			try 
			{
				Object[] obj = (Object[]) params.invoke(player, parameters);
				Boolean b = (Boolean)criterion.invoke(player, (Object[])
						params.invoke(player, parameters)
						);
				
				if((Boolean)criterion.invoke(player, (Object[])
						params.invoke(player, parameters)
						))
					return true;
				else
					return false;

			} 
			catch (IllegalArgumentException e) 
			{
				e.printStackTrace();
			} 
			catch (IllegalAccessException e) 
			{
				e.printStackTrace();
			} 
			catch (InvocationTargetException e) 
			{
				e.printStackTrace();
			}
			return false;
		}
	}
	
}
